﻿"""
工具类
包含各种辅助功能
"""

import os
import cv2
import numpy as np
from PIL import Image, ImageDraw, ImageFont
from typing import Optional
from src.config.settings import CHINESE_FONT_PATHS, FACE_RECOGNITION_CONFIG


class FontManager:
    """字体管理器"""
    
    def __init__(self):
        self.cv2_font = self.load_cv2_chinese_font()
    
    def load_cv2_chinese_font(self) -> Optional[str]:
        """加载OpenCV中文字体"""
        for font_path in CHINESE_FONT_PATHS:
            if os.path.exists(font_path):
                try:
                    # 尝试加载字体
                    font = ImageFont.truetype(font_path, 20)
                    return font_path
                except:
                    continue
        
        print("警告: 未找到合适的中文字体，将使用英文显示")
        return None
    
    def put_chinese_text(self, img: np.ndarray, text: str, position: tuple, 
                        font_size: int = 20, color: tuple = (0, 255, 0)) -> np.ndarray:
        """在OpenCV图像上绘制中文文本"""
        if self.cv2_font is None:
            # 如果没有PIL库，使用英文显示
            cv2.putText(img, text, position, cv2.FONT_HERSHEY_SIMPLEX, 0.7, color, 2)
            return img
        
        try:
            # 将OpenCV图像转换为PIL图像
            img_pil = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
            draw = ImageDraw.Draw(img_pil)
            
            # 加载字体
            font = ImageFont.truetype(self.cv2_font, font_size)
            
            # 绘制中文文本
            draw.text(position, text, font=font, fill=color)
            
            # 转换回OpenCV格式
            img = cv2.cvtColor(np.array(img_pil), cv2.COLOR_RGB2BGR)
        except Exception as e:
            # 如果中文显示失败，使用英文
            cv2.putText(img, text, position, cv2.FONT_HERSHEY_SIMPLEX, 0.7, color, 2)
        
        return img


class CameraManager:
    """摄像头管理器"""
    
    def __init__(self):
        self.cap = None
        self.is_camera_on = False
        self.camera_backend = None
    
    def open_camera(self, camera_index: int = 0) -> bool:
        """打开摄像头，支持多种后端"""
        # 尝试不同的摄像头后端
        backends = [
            (cv2.CAP_DSHOW, "DirectShow"),  # Windows推荐
            (cv2.CAP_MSMF, "Media Foundation"),  # Windows默认
            (cv2.CAP_V4L2, "Video4Linux2"),  # Linux
            (cv2.CAP_ANY, "Any")  # 自动选择
        ]
        
        for backend, backend_name in backends:
            try:
                print(f"尝试使用 {backend_name} 后端打开摄像头...")
                self.cap = cv2.VideoCapture(camera_index, backend)
                
                if self.cap.isOpened():
                    # 设置摄像头参数以提高稳定性
                    self.cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
                    self.cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)
                    self.cap.set(cv2.CAP_PROP_FPS, 30)
                    self.cap.set(cv2.CAP_PROP_BUFFERSIZE, 1)  # 减少缓冲区
                    
                    # 测试读取一帧
                    ret, frame = self.cap.read()
                    if ret and frame is not None:
                        self.camera_backend = backend_name
                        self.is_camera_on = True
                        print(f"摄像头打开成功，使用 {backend_name} 后端")
                        return True
                    else:
                        self.cap.release()
                        print(f"{backend_name} 后端无法读取帧")
                else:
                    print(f"{backend_name} 后端无法打开摄像头")
                    
            except Exception as e:
                print(f"{backend_name} 后端出错: {e}")
                if self.cap:
                    self.cap.release()
        
        print("所有摄像头后端都失败了")
        return False
    
    def close_camera(self):
        """关闭摄像头"""
        try:
            if self.cap:
                self.cap.release()
                self.cap = None
        except Exception as e:
            print(f"关闭摄像头时出错: {e}")
        finally:
            self.is_camera_on = False
    
    def read_frame(self) -> tuple:
        """读取帧"""
        if self.cap and self.is_camera_on:
            try:
                ret, frame = self.cap.read()
                # 检查帧是否有效
                if ret and frame is not None and frame.size > 0:
                    return ret, frame
                else:
                    return False, None
            except Exception as e:
                print(f"读取帧时出错: {e}")
                return False, None
        return False, None
    
    def is_opened(self) -> bool:
        """检查摄像头是否打开"""
        return self.is_camera_on and self.cap is not None and self.cap.isOpened()


class AttendanceManager:
    """考勤管理器"""
    
    def __init__(self):
        self.today_attendance = {}
        self.last_check_in_time = {}
        self.last_display_time = {}
        self.last_message_time = {}  # 记录每种消息类型的最后显示时间
        self.check_in_interval = FACE_RECOGNITION_CONFIG['check_in_interval']
        self.display_interval = FACE_RECOGNITION_CONFIG['display_interval']
    
    def can_check_in(self, employee_id: str) -> bool:
        """检查是否可以打卡"""
        import time
        current_time = time.time()
        
        # 如果员工没有打卡记录，可以打卡
        if employee_id not in self.last_check_in_time:
            return True
        
        # 检查是否超过打卡间隔
        elapsed_time = current_time - self.last_check_in_time[employee_id]
        return elapsed_time >= self.check_in_interval
    
    def can_display_message(self, employee_id: str, message_type: str = "default") -> bool:
        """检查是否可以显示消息"""
        import time
        current_time = time.time()
        
        # 创建消息类型的唯一标识
        message_key = f"{employee_id}_{message_type}"
        
        # 如果员工没有显示记录，可以显示
        if message_key not in self.last_message_time:
            return True
        
        # 检查是否超过显示间隔
        elapsed_time = current_time - self.last_message_time[message_key]
        return elapsed_time >= self.display_interval
    
    def update_check_in_time(self, employee_id: str):
        """更新打卡时间"""
        import time
        self.last_check_in_time[employee_id] = time.time()
    
    def update_display_time(self, employee_id: str, message_type: str = "default"):
        """更新显示时间"""
        import time
        message_key = f"{employee_id}_{message_type}"
        self.last_message_time[message_key] = time.time()
        # 保持向后兼容
        self.last_display_time[employee_id] = time.time()
    
    def add_attendance_record(self, employee_id: str, name: str, check_in_time: str, status: str = "正常"):
        """添加考勤记录"""
        self.today_attendance[employee_id] = {
            'name': name,
            'check_in_time': check_in_time,
            'status': status
        }
    
    def get_attendance_record(self, employee_id: str) -> Optional[dict]:
        """获取考勤记录"""
        return self.today_attendance.get(employee_id)
    
    def is_attended_today(self, employee_id: str) -> bool:
        """检查今天是否已打卡"""
        return employee_id in self.today_attendance
    
    def get_attendance_stats(self, total_employees: int) -> dict:
        """获取考勤统计"""
        checked_in = len(self.today_attendance)
        not_checked_in = total_employees - checked_in
        attendance_rate = (checked_in / total_employees * 100) if total_employees > 0 else 0
        
        return {
            'total': total_employees,
            'checked_in': checked_in,
            'not_checked_in': not_checked_in,
            'attendance_rate': attendance_rate
        }
    
    def cleanup_old_message_times(self):
        """清理过期的消息时间记录（超过1小时的记录）"""
        import time
        current_time = time.time()
        one_hour = 3600  # 1小时
        
        # 清理过期的消息时间记录
        expired_keys = []
        for message_key, timestamp in self.last_message_time.items():
            if current_time - timestamp > one_hour:
                expired_keys.append(message_key)
        
        for key in expired_keys:
            del self.last_message_time[key]
        
        # 清理过期的打卡时间记录
        expired_check_in_keys = []
        for employee_id, timestamp in self.last_check_in_time.items():
            if current_time - timestamp > one_hour:
                expired_check_in_keys.append(employee_id)
        
        for key in expired_check_in_keys:
            del self.last_check_in_time[key]
        
        # 清理过期的显示时间记录
        expired_display_keys = []
        for employee_id, timestamp in self.last_display_time.items():
            if current_time - timestamp > one_hour:
                expired_display_keys.append(employee_id)
        
        for key in expired_display_keys:
            del self.last_display_time[key]


class FileManager:
    """文件管理器"""
    
    @staticmethod
    def ensure_directory_exists(directory: str):
        """确保目录存在"""
        if not os.path.exists(directory):
            os.makedirs(directory)
    
    @staticmethod
    def export_to_csv(data: list, headers: list, file_path: str) -> bool:
        """导出数据到CSV文件"""
        try:
            import csv
            with open(file_path, 'w', newline='', encoding='utf-8') as f:
                writer = csv.writer(f)
                writer.writerow(headers)
                writer.writerows(data)
            return True
        except Exception as e:
            print(f"导出CSV失败: {e}")
            return False
